/**
 * 插件初始化
 * @link https://www.kancloud.cn/cleverstone/ymb2
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

// angular应用初始化
+function (global, angular, ym2, toastr, jQuery, swal, yii, ymSpinner, layui, UE, _, Sortable, ym2Encrypt, xmSelect, tinyMCE) {

    "use strict";

    var ym2Module;

    // 注册angular-select2插件模块
    var _dependenciesModule = [];
    try { angular.module("ui.select2"); _dependenciesModule.push("ui.select2"); } catch (e) {}
    try { angular.module("ym2.upload"); _dependenciesModule.push("ym2.upload") } catch (e) {}
    ym2Module = angular.module("ym2.module", _dependenciesModule);

    // 注册服务
    ym2Module.factory("ym2", function () {
        // ym2
        return ym2 || {};
    }).factory("toastr", function () {
        // toastr
        return toastr || {};
    }).factory("jQuery", function () {
        // jQuery3
        return jQuery || {};
    }).factory("swal", function () {
        // sweetalert
        return swal || {};
    }).factory('yii', function () {
        // yii2
        return yii || {};
    }).factory("ymSpinner", function () {
        // spinner
        return ymSpinner || {};
    }).factory("layui", function () {
        // layui
        return layui || {};
    }).factory("ue", function () {
        // ueditor
        return UE || {};
    }).factory("lodash", function () {
        // lodash
        return _ || {};
    }).factory("Sortable", function () {
        return Sortable || {};
    }).factory("ym2Encrypt", function () {
        return ym2Encrypt || {};
    }).factory("xmSelect", function () {
        return xmSelect || {};
    }).factory("tinyMCE", function () {
        return tinyMCE || {};
    });

    // 注册过滤器
    ym2Module.filter("toHtml", ['$sce', function ($sce) {
        //展示html
        return function (value) {
            return $sce.trustAsHtml(String(value));
        };
    }]).filter("default", function () {
        //设置默认值
        return function (value, defaultVal) {
            return value || defaultVal;
        };
    }).filter("toUpper", function () {
        //字母大写
        return function (value) {
            if (value) {
                return String(value).toUpperCase();
            } else {
                return "文件";
            }
        };
    });

    // 注册指令
    ym2Module.directive('ym2Page', ["$compile", function ($compile) {
        // 分页指令
        return {
            restrict: 'A',
            replace: true,
            scope: false,
            link: function (scope, element, attrs) {
                scope.$watch(
                    function (scope) {
                        return scope.$eval(attrs.ym2Page);
                    },
                    function (value) {
                        element.html(value);
                        $compile(element.contents())(scope);
                    }
                );
            }
        };
    }]).directive('onFinishRender', ["$timeout", function ($timeout) {
        // 监听ng-repeat执行完成指令
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                if (scope.$last === true) {
                    $timeout(function () {
                        // ev-repeat-finished
                        scope.$emit(attr.onFinishRender);
                    });
                }
            }
        };
    }]).directive('stringToNumber', function () {
        // 当前input控件是number时，自动转换ngModel的数据类型。
        return {
            require: 'ngModel',
            link: function (scope, element, attrs, ngModel) {
                // 输出转换为字符串
                ngModel.$parsers.push(function (value) {
                    if (value !== void 0 && value !== null) {
                        return '' + value;
                    } else {
                        return '';
                    }
                });
                // 格式化
                ngModel.$formatters.push(function (value) {
                    return parseFloat(value);
                });
            }
        };
    }).directive("layuiFormRender", ["layui", function (layui) {
        // 解决layui表单中多选/开关/单选/下拉选择不兼容angular问题
        return {
            restrict: 'A',
            require: "ngModel",
            link: function (scope, element, attrs, ngModel) {
                scope.$watch(
                    function () {
                        return ngModel.$modelValue;
                    },
                    function () {
                        layui.form.render( element );
                    }
                );
            },
        };
    }]).directive("ym2Laydate", ["layui", function (layui) {
        // laydate日期插件渲染
        return {
            restrict: 'A',
            link: function (scope, element, attr) {
                var range = attr.ym2Range;
                var type = attr.ym2Type;
                var options = {
                    elem: element,
                    type: type,
                    calendar: true, //展示节日
                    shortcuts: [ //默认快捷操作
                        {
                            text: "上一月",
                            value: function(){
                                var now = new Date();
                                var month = now.getMonth() - 1;
                                now.setMonth(month);
                                // 若上个月数不匹配，则表示天数溢出
                                if (now.getMonth() !== month) {
                                    now.setDate(0); // 重置天数
                                }
                                return [now];
                            }
                        },
                        {
                            text: "下一月",
                            value: function(){
                                var now = new Date();
                                var month = now.getMonth() + 1;
                                now.setMonth(month);
                                // 若下个月数不匹配，则表示天数溢出
                                if (now.getMonth() !== month) {
                                    now.setDate(0); // 重置天数
                                }
                                return [now];
                            }
                        },
                        {
                            text: "昨天",
                            value: function(){
                                var now = new Date();
                                now.setDate(now.getDate() - 1);
                                return now;
                            }
                        },
                        {
                            text: "明天",
                            value: function(){
                                var now = new Date();
                                now.setDate(now.getDate() + 1);
                                return now;
                            }
                        },
                        {
                            text: "今天",
                            value: function(){
                                return Date.now();
                            }
                        },
                    ],
                    done: function (value, date, endDate) {
                        /* 触发input事件 */
                        jQuery(this.elem).val(value).trigger("change");
                    },
                };

                //当前日期/时间信息
                var _nowDate = new Date();
                var _curYear = _nowDate.getFullYear();
                var _curMonth = _nowDate.getMonth();
                var _curDay = _nowDate.getDate();

                if (Number(range) === 1) {
                    options.range = '/';
                    // 2.8+
                    // 是否开启日期范围选择时的区间联动标注模式，该模式必须开启 range 属性才能生效。
                    options.rangeLinked = true;

                    //重写shortcuts
                    options.shortcuts = [
                        {
                            text: "最近一月",
                            value: function () {
                                return [
                                    /** 包含今天，所有需要减去29天 */
                                    new Date(_curYear, _curMonth, _curDay - 29),
                                    new Date(_curYear, _curMonth, _curDay, 23, 59, 59)
                                ];
                            },
                        },
                        {
                            text: "最近一周",
                            value: function () {
                                return [
                                    /** 包含今天，所有需要减去6天 */
                                    new Date(_curYear, _curMonth, _curDay - 6),
                                    new Date(_curYear, _curMonth, _curDay, 23, 59, 59)
                                ];
                            },
                        },
                        {
                            text: "最近三天",
                            value: function () {
                                return [
                                    /** 包含今天，所有需要减去2天 */
                                    new Date(_curYear, _curMonth, _curDay - 2),
                                    new Date(_curYear, _curMonth, _curDay, 23, 59, 59)
                                ];
                            },
                        },
                        {
                            text: "上一月",
                            value: function(){
                                return [
                                    new Date(_curYear, _curMonth - 1, 1),
                                    new Date(_curYear, _curMonth, 0, 23, 59, 59)
                                ];
                            }
                        },
                        {
                            text: "下一月",
                            value: function(){
                                return [
                                    new Date(_curYear, _curMonth + 1, 1),
                                    new Date(_curYear, _curMonth + 2, 0, 23, 59, 59)
                                ];
                            }
                        },
                        {
                            text: "当月",
                            value: function(){
                                return [
                                    new Date(_curYear, _curMonth, 1),
                                    new Date(_curYear, _curMonth + 1, 0, 23, 59, 59)
                                ];
                            }
                        },
                        {
                            text: "昨天",
                            value: function(){
                                return [
                                    new Date(_curYear, _curMonth, _curDay - 1),
                                    new Date(_curYear, _curMonth, _curDay - 1, 23, 59, 59)
                                ];
                            }
                        },
                        {
                            text: "明天",
                            value: function(){
                                return [
                                    new Date(_curYear, _curMonth, _curDay + 1),
                                    new Date(_curYear, _curMonth, _curDay + 1, 23, 59, 59)
                                ];
                            }
                        },
                        {
                            text: "今天",
                            value: function(){
                                return [
                                    new Date(_curYear, _curMonth, _curDay),
                                    new Date(_curYear, _curMonth, _curDay, 23, 59, 59)
                                ];
                            }
                        },
                    ];
                } else if (type === 'datetime') {
                    // 2.8+
                    options.fullPanel = true;
                }

                var allowShortcutsType = ['datetime', 'date'];
                if ( allowShortcutsType.indexOf( type ) === -1 ) {
                    //!datetime、!date
                    delete options.shortcuts;
                } else {
                    //datetime、date
                    options.mark = function (ymd, render) {
                        var now = new Date();
                        var y = ymd.year;
                        var m = ymd.month;
                        var d = ymd.date;

                        // 字符串
                        if (y === now.getFullYear() && m === (now.getMonth() + 1) && d === now.getDate()) {
                            return render('今天');
                        }
                    };

                }

                layui.laydate.render(options);
            }
        };
    }]).directive("ym2BootstrapPlugin", function () {
        // bootstrap插件初始化
        return {
            restrict: "A",
            link: function (scope, element, attr) {
                // 插件目标元素已初始化完成
                if ( attr.initialized ) {
                    return;
                }
                var pluginName = attr.ym2BootstrapPlugin;
                var config = attr.pluginConfig || "";
                try {
                    config && eval("config=" + config);
                } catch (e) {
                    config = "";
                }

                if (config !== "") {
                    element[pluginName](config);
                } else {
                    element[pluginName]();
                }

                //标记
                element.attr('data-initialized', true);
            },
        };

    }).directive("xmSelect", ["xmSelect", "ym2", function (xmSelect, ym2) {
        // xm-select angular数据双向绑定
        return {
            restrict: "A",
            scope: false,
            require: "ngModel",
            link: function (scope, element, attr, controller) {
                var options = scope.$eval(attr.xmSelect);
                var itemOptions = attr.watchData;
                var instance;
                var changeValue;
                var initValue;
                var valueField;
                var set_view_value = function (value) {
                    value = value || [];
                    if ( ym2.typeOf( value ) !== "array" ) {
                        value = new Array( value );
                    }

                    instance.setValue( value );
                };

                if (options.prop && options.prop.value) {
                    valueField = options.prop.value;
                } else {
                    valueField = "value";
                }

                options.el = "#" + attr.id;
                options.on = function (data) {
                    changeValue = options.radio ? "" : []

                    data.arr.forEach(function (value) {
                        if (options.radio) {
                            changeValue = value[valueField];
                        } else {
                            changeValue.push(value[valueField]);
                        }
                    });

                    controller.$setViewValue(changeValue); //model setter
                };

                instance = xmSelect.render(options);
                initValue = instance.getValue(options.radio ? "valueStr" : "value");
                instance.oldValue = initValue;
                controller.$setViewValue(initValue);//model setter

                scope.$watch(function () {
                    return controller.$modelValue;
                }, function (newVal, oldVal) {
                    set_view_value( newVal ); //view setter
                });

                if ( itemOptions ) {
                    scope.$watch( function () {
                        return scope.$eval( itemOptions );
                    }, function (nv, ov) {
                        //非undefined || 非null || 非false || 非空字符
                        if ( nv ) {
                            instance.update({
                                data: nv,
                            });

                            //解决重载下拉选择项后，视图和模型中的选中项错乱。
                            //把视图和模型都清空选择
                            controller.$setViewValue( options.radio ? "" : [] );

                        }
                    });
                }

            },
        };
    }]).directive("ym2Star", ["layui", "ym2", function (layui, ym2) {
        return {
            restrict: "A",
            scope: false,
            require: "ngModel",
            link: function (scope, element, attr, controller) {
                var eleDom = element[0];
                var options = scope.$eval(attr.ym2Star) || {};
                var rate = layui.rate;

                //格式化配置
                options.elem =  eleDom;
                options.value = controller.$modelValue;
                if ( options.setText ) {
                    var customTxt = options.setText;
                    options.setText = function (value) {
                        this.span.text(customTxt[value] || ( value + "星"));
                    };
                }

                if ( !options.theme ) {
                    options.theme = ym2.getAppThemeColor();
                }

                //更新vm
                options.choose = function (value) {
                    controller.$setViewValue(value);
                };

                scope.$watch(function () {
                    return controller.$modelValue;
                }, function (newVal) {
                    newVal = newVal || 0;
                    options.value = newVal;
                    //更新视图
                    rate.render(options);
                });
            },
        };
    }]).directive('ngxBindHtml', ["$parse", function ($parse) {
        return {
            restrict: "A",
            replace: false,
            link: function (scope, ele, attr) {
                // ele.html( scope.$eval( attr.ngxBindHtml ) ); //等同
                ele.html( $parse( attr.ngxBindHtml )( scope ) );
            },

        };
    }]).directive('ym2EsSelect', ["Sortable", "$compile", "jQuery", function (Sortable, $compile, jQuery) { //弹性选择控件
        return {
            restrict: "A",
            replace: false,
            template: '<div class="js_draggable d-flex align-items-center flex-wrap">\
                            <div class="ym2-es-select-item position-relative m-2" style="width:fit-content;" ng-repeat="(i, item) in xngModel">\
                                <span style="position:absolute;right:-10px;top:-10px;" class="x bi bi-x-circle layui-font-14" ng-click="removeOne(i)"></span>\
                                <div ngx-bind-html="$compileHtml( item[ nameField ] )"></div>\
                            </div>\
                       </div>\
                       <div title="{{ placeholder }}" class="ym2-es-select-to-select" ng-click="toSelect()">\
                            <i class="bi bi-plus-circle-dotted"></i>\
                       </div>',
            scope: {
                onClickSelect: "&",
                xngModel: "=",
            },
            link: function (scope, element, attr) {
                var options = JSON.parse(attr.ym2EsSelect);
                scope.nameField = options.nameField;
                scope.placeholder = attr.placeholder || "点击上传";

                scope.$compileHtml = function (v) {
                    // 参数值显式转为字符串类型
                    v = String(v);
                    var htmlTokenCount = 0;
                    try {
                        // 参数值为Text时，jQuery不解析。
                        htmlTokenCount = jQuery( v ).length;
                    } catch (e) {
                        console.log('html解析失败判断为text：' + v);
                    }
                    return htmlTokenCount > 0 ? $compile( v )( scope ) : v;
                };

                //排序
                Sortable.create(element.find('.js_draggable').get(0), {
                    draggable: ".ym2-es-select-item",
                    handle: ".ym2-es-select-item",
                    // animation: 150,
                    animation: 300,
                    // easing: "cubic-bezier(1, 0, 0, 1)",
                    easing: "linear",
                    // 结束拖拽
                    onEnd: function( /**Event*/ evt) {
                        var oldIndex = evt.oldIndex;
                        var newIndex = evt.newIndex;
                        if ( oldIndex !== newIndex ) {
                            var list = scope.xngModel;
                            var newList = [];
                            var changeItem = list[oldIndex];
                            list.forEach(function (value, index) {
                                if (oldIndex === index) { return; }
                                if (oldIndex > newIndex && newIndex === index) { newList.push(changeItem); }
                                newList.push(value);
                                if (oldIndex < newIndex && newIndex === index) { newList.push(changeItem); }
                            });

                            scope.$apply(function () {
                                //下一个宏任务执行
                                scope.xngModel = newList;
                            });

                        }

                    },
                });

                //删除项
                scope.removeOne = function (i) {
                    scope.xngModel.splice(i, 1);
                }

                //弹出选择项
                scope.toSelect = function () {
                    scope.onClickSelect()(options);
                };
            },
        };
    }]).directive('ngxSelection', [function () {
        //表单控件input、textarea初始化和聚焦时高亮选中内容。
        return {
            restrict: 'A',
            replace: false,
            scope: false,
            link: function (scope, element, attribute) {
                element.focus(function () {
                    jQuery(this).select();
                });

                setTimeout(function () {
                    element.focus();
                });
            },
        };
    }]).directive('ngxTransfer', ['layui', function (layui) {
        // 定义layui穿梭框(transfer)控件angular指令。
        return {
            restrict: 'A',
            replace: false,
            scope: false,
            require: "ngModel",
            link: function (scope, ele, attr, controller) {
                let transfer = layui.transfer,
                    options = JSON.parse(attr.ngxTransfer),
                    dblclickFunc;
                try {
                    let newFunc = new Function(attr.dblclick);
                    dblclickFunc = newFunc() || null;
                } catch {
                    console.log('error', attr.dblclick);
                    dblclickFunc = null;
                }

                options.elem = "#"+attr.id;
                options.id = attr.id;
                options.onchange = function (data, index) {
                    controller.$setViewValue(
                        transfer.getData(options.id).map(function (value) {
                            return value.value;
                        })
                    );
                };
                options.dblclick = dblclickFunc;

                // 渲染初始化
                transfer.render(options);

                // 监听scope变化
                scope.$watch(function () {
                    return controller.$modelValue;
                }, function (newValue) {
                    // 初始化或重置控件默认值。
                    transfer.reload(options.id, {
                        value: newValue,
                    });
                });
            },
        };
    }]).directive('ngxColorpicker', ['layui', function (layui) {
        return {
            restrict: 'A',
            replace: false,
            scope: false,
            require: "ngModel",
            link: function (scope, ele, attr, controller) {
                let colorpicker = layui.colorpicker,
                    options = JSON.parse(attr.ngxColorpicker),
                    changeHandler, cancelHandler, closeHandler;
                try {
                    let newFunc = new Function(attr.changehandler);
                    changeHandler = newFunc() || null;
                } catch {
                    console.log('error', attr.changehandler);
                    changeHandler = null;
                }
                try {
                    let newFunc = new Function(attr.cancelhandler);
                    cancelHandler = newFunc() || null;
                } catch {
                    console.log('error', attr.cancelhandler);
                    cancelHandler = null;
                }
                try {
                    let newFunc = new Function(attr.closehandler);
                    closeHandler = newFunc() || null;
                } catch {
                    console.log('error', attr.closehandler);
                    closeHandler = null;
                }

                options.elem = "#"+attr.id;
                options.change = changeHandler;
                options.cancel = cancelHandler;
                options.close = closeHandler;
                options.done = function (value) {
                    controller.$setViewValue(value);
                };

                // 监听scope变化
                scope.$watch(function () {
                    return controller.$modelValue;
                }, function (newValue) {
                    // 重新渲染
                    options.color = newValue;
                    colorpicker.render(options);
                });
            },
        };
    }]).directive('ngxLayuiform', ['layui', function (layui) {
        return {
            restrict: 'A',
            replace: false,
            scope: false,
            require: "ngModel",
            link: function (scope, ele, attr, controller) {
                let form = layui.form;

                // 监听select变化
                form.on(attr.ngxLayuiform + '('+attr.layFilter+')', function (obj) {
                    controller.$setViewValue(obj.value, 'change');
                });

                // 监听scope变化
                scope.$watch(function () {
                    return controller.$modelValue;
                }, function () {
                    form.render(ele);
                });
            },
        };
    }]);

    // 定义http拦截器
    ym2Module.factory("httpInterceptor", ["$q", function ($q) {
        // http拦截器
        return {
            'responseError': function (response) { // 错误拦截
                return $q.reject(response);
            },
            'response': function (response) {     // 响应拦截
                return response;
            },
            'request': function (config) {        // 请求拦截
                // 当时请求方法是`POST`时,自动携带[csrf]令牌,并自动参数序列化.
                var method = config.method;
                var bodyParams = config.data || {};
                if (method.toUpperCase() === 'POST') {
                    bodyParams[yii.getCsrfParam()] = yii.getCsrfToken();

                    var contentType = config.headers['Content-Type'];
                    if (contentType && ym2.typeOf(contentType) === 'string') {
                        // application/x-www-form-urlencoded
                        if (contentType.indexOf('application/x-www-form-urlencoded') !== -1) {
                            config.data = jQuery.param(bodyParams);
                        }

                        // application/json
                        if (contentType.indexOf('application/json') !== -1) {
                            config.data = JSON.stringify(bodyParams);
                        }

                        // ...
                    }
                    // 其他`content-type`不用处理，如：undefined、multipart/form-data
                }

                return config;
            },
            'requestError': function (config) {    // 请求错误拦截
                return $q.reject(config);
            }
        };
    }]).config(["$httpProvider", function ($httpProvider) {
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8';
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

        // 添加拦截器
        $httpProvider.interceptors.push('httpInterceptor');
    }]);


    // 全局定义ym2应用
    global.ym2App = angular.module("ym2.app", ["ym2.module", "ngFileUpload"]);

    // 禁止a标签href中, 以下协议标记unsafe
    global.ym2App.config(['$compileProvider', function ($compileProvider) {
        if ($compileProvider.imgSrcSanitizationWhitelist) $compileProvider.imgSrcSanitizationWhitelist(/^\s*(https?|s?ftp|mailto|tel|webcal|local|file|data|blob|javascript):/);
        if ($compileProvider.aHrefSanitizationWhitelist) $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|s?ftp|mailto|tel|webcal|local|file|data|blob|javascript):/);
    }]);

}(
    window,
    window.angular,
    window.ym2,
    window.toastr,
    window.jQuery,
    window.swal,
    window.yii,
    window.ymSpinner,
    window.layui,
    window.UE,
    window._,
    window.Sortable,
    window.ym2Encrypt,
    window.xmSelect,
    window.tinyMCE
);

// 插件初始化
-function (global, top, jQuery, toastr, layui, UE, ym2Fullscreen, tinyMCE, ym2, ymSpinner) {

    "use strict";

    // 设置select2主题
    if (typeof jQuery.fn !== 'undefined' && jQuery.fn.select2) {
        /* Sets select2 bootstrap4-theme */
        jQuery.fn.select2.defaults.set("theme", "bootstrap4");
        jQuery.fn.select2.defaults.set("language", "zh-CN");
    } else {
        console.warn("The select2 plugin theme and i18n are not set.");
    }

    // 初始化toastr
    if (jQuery && typeof toastr !== 'undefined' && toastr.options) {
        toastr.options.closeButton = false;
        toastr.options.progressBar = false;
        toastr.options.timeOut = 3000; // How long the toast will display without user interaction
        toastr.options.extendedTimeOut = 3000; // How long the toast will display after a user hovers over it
        toastr.options.showMethod = 'slideDown';
        // toastr.options.showMethod = 'fadeIn';
        toastr.options.hideMethod = 'fadeOut';
        toastr.options.showEasing = "swing";
        toastr.options.hideEasing = "linear";
        toastr.options.closeMethod = 'fadeOut';
        toastr.options.closeDuration = 300;
        toastr.options.positionClass = 'toast-top-center';
    } else {
        console.warn("The toastr plugin is not initialized.");
    }

    // IMG查看全图
    if (jQuery && top.layui) {
        jQuery(document).on("click", "[ym2-full-image]", function () {
            var that = this;
            var igDom = jQuery(that).closest("[ym2-image-group]");
            var start = 0;
            var data = [];

            if (igDom.length) {
                igDom.find("[ym2-full-image]").each(function (index, currentDom) {
                    if (currentDom === that) {
                        start = index;
                    }

                    var $currentDom = jQuery(currentDom);
                    data.push({
                        "alt": $currentDom.attr("alt") || "",
                        "src": $currentDom.attr("src") || $currentDom.attr("srcx"),
                        "thumb": $currentDom.attr("thumb") || $currentDom.attr("src") || $currentDom.attr("srcx"),
                    });
                });
            } else {
                var $that = jQuery(that);
                data.push({
                    "alt": $that.attr("alt") || "",
                    "src": $that.attr("src") || $that.attr("srcx"),
                    "thumb": $that.attr("thumb") || $that.attr("src") || $that.attr("srcx"),
                });
            }

            top.layui.layer.photos({
                photos: {
                    "title": "查看大图",
                    "start": start,
                    "data": data,
                },
            });
        });
    } else {
        console.warn("The large image is not bound.");
    }

    // 初始化ueditor
    /** @deprecated 已不再用维护，体验不好。 */
    if (jQuery && UE) {
        var ueditorContianer = {};
        jQuery("[ym2-ueditor]").each(function () {
            var id = this.id;
            var config = this.getAttribute("ym2-ueditor") || "{}";
            try {
                eval("config=" + config);
            } catch (e) {
                config = {};
            }

            config.initialFrameWidth = config.initialFrameWidth || config.width || "100%";
            config.initialFrameHeight = config.initialFrameHeight || config.height || 500;
            config.autoHeightEnabled = config.autoHeightEnabled || false;

            delete config.width;
            delete config.height;

            ueditorContianer[id] = UE.getEditor(id, config);
        });

        // 获取已初始化的ueditor实例
        UE.getInstanceById = function (id) {
            return ueditorContianer[id] || null;
        };
    } else {
        // console.warn("【Baidu Editor(UEditor)】did not initialize the binding.");
    }

    //初始化tinyMCE
    +function ($, tinyMCE, top, ym2) {
        if (tinyMCE) {
            $("[ym2-tinymce]").each(function () {
                var id = this.id;
                var config = this.getAttribute("ym2-tinymce") || "{}";
                try {
                    eval("config=" + config);
                } catch (e) {
                    config = {};
                }

                var defaultOptions = {
                    selector: "#" + id,
                    height: 600,
                    language: "zh_CN",
                    promotion: false,
                    branding: true,
                    license_key: "gpl",//开源许可类型
                    autosave_ask_before_unload: true,
                    autosave_interval: '10s',
                    autosave_prefix: '{path}{query}-{id}-',
                    autosave_restore_when_empty: false,
                    autosave_retention: '30m',
                    image_advtab: true,
                    image_uploadtab: true,
                    image_caption: true,
                    importcss_append: true,
                    skin: 'snow',
                    content_css: 'tinymce-5',
                    icons: 'thin',
                    plugins: 'code preview importcss searchreplace autolink autosave directionality visualblocks visualchars fullscreen image link media codesample table charmap pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help charmap quickbars emoticons',
                    mobile: {
                        plugins: 'code preview importcss searchreplace autolink autosave directionality visualblocks visualchars fullscreen image link media codesample table pagebreak nonbreaking anchor insertdatetime advlist lists wordcount help charmap quickbars emoticons',
                    },
                    menubar: 'file edit view insert format tools table help',
                    toolbar: "preview code restoredraft | undo redo | blocks fontsizeinput | bold italic strikethrough hr | align numlist bullist | link table | image media | lineheight  outdent indent | forecolor backcolor removeformat | charmap emoticons | print pagebreak anchor codesample | ltr rtl | fullscreen", // Note: if a toolbar item requires a plugin, the item will not present in the toolbar if the plugin is not also loaded.
                    toolbar_mode: 'sliding',
                    quickbars_insert_toolbar: 'emoticons image quicktable',
                    //quickimage：快捷从本地选择图片，上传后是base64格式，只能用于小体积图片，大图片不合适。
                    quickbars_selection_toolbar: 'bold italic p h3 h4 h5 blockquote quicklink image quicktable alignleft aligncenter alignright removeformat',
                    contextmenu: 'link image editimage table insertdatetime',
                    file_picker_callback: function (cb, value, meta) {
                        //成功回调 arg1: URL arg2：附件元素其他属性
                        //@see https://www.tiny.cloud/docs/tinymce/latest/file-image-upload/#file_picker_callback
                        // console.log(cb);
                        //输入框中的“源”值
                        // console.log(value);
                        //图片： {filetype: 'image', fieldname: 'src'}
                        //视频： {filetype: 'media', fieldname: 'source'}
                        //链接： {filetype: 'file', fieldname: 'url', original: {original:{value:""}}}
                        // console.log(meta);
                        clickUpload(meta).then(function (info) {
                            cb( info.shift().url );
                        });
                    },
                };

                Object.assign(defaultOptions, config);
                tinyMCE.init(defaultOptions)
            });
            //点击上传
            function clickUpload (meta) {
                var scenarioMap,//当前上传场景映射
                    labelMsg,//标签提示
                    layerScreenObj = ym2.layerScreenOptions("917px"), //layer screen obj
                    maxNumber = 1;//可以选中附件的最大数量
                switch (meta.filetype) {
                    case "image"://图片
                        scenarioMap = ["IMAGE"];
                        labelMsg = "请选择一张图片!";
                        break;
                    case "media"://视频
                        scenarioMap = ["VIDEO"];
                        labelMsg = "请选择一段视频!";
                        break;
                    default://file|other
                        scenarioMap = ["IMAGE", "VIDEO", "AUDIO", "OTHER"];
                        labelMsg = "请选择一份文件!";
                }
                var provideResults = function (result) {};

                var refererName = ym2.layerRefererWindowName( "self" );
                //加载中
                // var loadingFlag = top.ymSpinner.show('加载中...');
                // iframe 模态框
                top.layer.open({
                    type: 2, // iframe
                    //skin: 'layui-layer-win10',
                    area: [layerScreenObj.width, "655px"],
                    title: "文件上传",
                    shade: 0.3, // 遮罩透明度
                    shadeClose: false, // 点击遮罩区域，关闭弹层
                    closeBtn: 1,
                    maxmin: false, // 允许全屏最小化
                    anim: 0, // 0-6 的动画形式，-1 不开启
                    scrollbar: false, // 打开弹层时，是否允许浏览器出现滚动条。
                    content: ym2.addUrlQueryParam("/__upload/index", {}),
                    success: function(layero, index, that){
                        // top.ymSpinner.hide( loadingFlag );
                        // 弹层的最外层元素的 jQuery 对象
                        //console.log(layero);
                        // 弹层的索引值
                        //console.log(index);
                        // 弹层内部原型链中的 this --- 2.8+
                        //console.log(that);
                        // 获取iframe的窗口对象, 添加来源追踪
                        var iframeWin = top[ layero.find("iframe")[0]["name"] ];
                        iframeWin.__REFERER_WIN_NAME = refererName;
                        iframeWin.onFileSelected = function (selectedData) {
                            var result = [];
                            selectedData.forEach(function (value, index) {
                                var type = value.type;
                                if (scenarioMap.indexOf(type) > -1) {
                                    result.push({
                                        link: value.link,
                                        url: value.url,
                                        type: type,
                                        ext: value.ext,
                                    });
                                }
                            });
                            if (!result.length || result.length > maxNumber) {
                                top.toastr.error(labelMsg);
                                return false;
                            }

                            provideResults(result);
                            return true;

                        };
                    },
                });

                return new Promise(function (resolve, reject) {
                    provideResults = function (result) {
                        resolve(result);
                    };
                });
            }
        } else {
            // console.warn("【TinyMCE Editor】did not initialize the binding.");
        }
    }(jQuery, tinyMCE, top, ym2); //require: layer、toastr

    // 解决layui表单部分控件无法触发$setter问题
    if (layui) {
        layui.form.on("checkbox(ym2_form_checkbox)", function (data) {
            // checkbox trigger change
            layui.jquery(data.elem).trigger("change");
        });
        layui.form.on("switch(ym2_form_switch)", function (data) {
            // switch trigger change
            layui.jquery(data.elem).trigger("change");
        });
        layui.form.on("radio(ym2_form_radio)", function (data) {
            // radio trigger change
            layui.jquery(data.elem).trigger("change");
        });
        layui.form.on("select(ym2_form_select)", function (data) {
            // select trigger change
            layui.jquery(data.elem).trigger("change");
        });
    } else {
        console.warn("The layui form control is not bound to angular js.");
    }

    // 窗口全屏
    if (jQuery && ym2Fullscreen) {
        // 监听
        jQuery(document).on("click", ".ym2AppScreen", function (e) {
            if (ym2Fullscreen.isFullscreen()) {
                // 关闭
                ym2Fullscreen.fullClose().then(function () {
                    global.localStorage.removeItem("ym2_is_fullscreen");
                });
            } else {
                // 打开
                ym2Fullscreen.fullScreen().then(function () {
                    global.localStorage.setItem("ym2_is_fullscreen", "yes");
                });
            }
        });
    } else {
        console.warn("The JS full-screen plug-in is not bound.");
    }
    // 文本复制,支持dom异步渲染
    if (jQuery && layui) {
        /**
         * 示例：
         * <button class="layui-btn layui-btn-sm" ym2-clipboard="this is duplicate content.">
         *     复制
         * </button>
         */
        jQuery(document).on("click", "[ym2-clipboard]", function (e) {
            var lay = layui.lay;
            var layer = layui.layer;
            var txt = jQuery(this).attr("ym2-clipboard");
            var othis = this;

            lay.clipboard.writeText({
                text: txt,
                done: function() {
                    // alert('😘复制成功!');
                    // layer.msg("已复制", {
                    //     offset: "16px",
                    // });
                    layer.tips('😘复制成功~', othis, {
                        tips: 1
                    });
                },
                error: function() {
                    // alert('🥵复制失败!');
                    // layer.msg("复制失败", {
                    //     offset: "16px",
                    // });
                    layer.tips('🥵复制失败~', othis, {
                        tips: 1
                    });
                }
            });

        });

    } else {
        console.warn("The clipboard isn't initialized.")
    }

    // html a标签打开新的window窗口 target="_open"
    !function () {
        var windowObjectReference = null;
        var previousURL;
        var windowFeatures = "width=800,height=500,left=500,top=200,toolbar=0,location=0,menubar=0";
        function openRequestedSingleTab(url) {
            if (windowObjectReference === null || windowObjectReference.closed) {
                windowObjectReference = window.open(url, "SingleSecondaryWindowName", windowFeatures);
            } else if (previousURL !== url) {
                windowObjectReference = window.open(url, "SingleSecondaryWindowName", windowFeatures);
                /* 如果要加载的资源是不同的，则我们会将其加载到已打开的辅助窗口中，然后将该窗口拉回到其父窗口的顶部或前面。*/
                windowObjectReference.focus();
            } else {
                windowObjectReference.focus();
            }
            previousURL = url;
            /* 解释：我们存储当前的 url，以便在再次调用此函数时对 url
               进行比较。 */
        }

        jQuery(document).on("click", "a[target='_open']", function (event) {
            openRequestedSingleTab(event.currentTarget.href);
            event.preventDefault();
        });
    }();

    // ESC键逐层关闭layer-iframe窗口
    function keydownListenerHandler(event) {
        let tar = event.target;
        //当键盘按键是ESC时，关闭最近一次layui-iframe/bootstrap-modal/sweetalert2窗口。
        if(
            event.keyCode === 27 // keyboard-key是"Escape"
            && jQuery(tar).closest('.swal2-container').length === 0 // 兼容sweetalert2
            && jQuery(tar).closest('.modal').length === 0 // 兼容bootstrap-modal
        ) {
            //获取最近一次打开的layui-iframe窗口名
            function getLastIframeName() {
                let frames = top.frames;
                let frameCount = frames.length;
                if (frameCount > 0) {
                    return frames[frameCount - 1].name ?? '';
                }
                return '';
            }

            let iframeName = getLastIframeName();
            if (iframeName.length > 0) {
                let index = top.layer.getFrameIndex(iframeName);
                top.layer.close(index ?? 0);
            }
        }

        //当键盘按键是F1时，阻止浏览器默认行为，切换左侧菜单隐藏/展示。
        if (event.key === 'F2') {
            jQuery('[ym2-kb-accordion]').trigger('click');
        }
    }
    // 节流处理，防止键盘键按下不抬，事件监听器死循环。
    let throttleFunc = _.throttle(keydownListenerHandler, 300, { trailing: false });
    jQuery(document).on('keydown', throttleFunc);

    // 监听按钮打印事件
    jQuery(document).on("click", "button[type=print]", function () {
        global.print();
    });

}(
    window,
    top,
    window.jQuery,
    window.toastr,
    window.layui,
    window.UE,
    window.ym2Fullscreen,
    window.tinyMCE,
    window.ym2,
    window.ymSpinner
);